package com.weibo.berkeleydb;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.CursorConfig;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
/**
 * Created by zhangzhen on 2017/1/10.
 */
public class BDBUtil<K,V> {

    private static final Log log = LogFactory.getLog(BDBUtil.class);
    private Environment env = null;
    private EnvironmentConfig envCfig = null;
    private Database db = null;
    private DatabaseConfig dbCfig = null;
    private File file = null;

    public BDBUtil(String dbName) throws DatabaseException {
        envCfig = new EnvironmentConfig();
        envCfig.setAllowCreate(true);
        //数据库的地址
        file = new File("db");
        env = new Environment(file, envCfig);
        dbCfig = new DatabaseConfig();
        dbCfig.setAllowCreate(true);
        db = env.openDatabase(null, dbName, dbCfig);
    }
    public boolean put(K key, V value,boolean isOverwrite){

        try {
            DatabaseEntry beanKeyEntry = new DatabaseEntry(key.toString().getBytes("utf-8"));
            DatabaseEntry beanValEntry = new DatabaseEntry();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(value);
            } catch (IOException e) {
                e.printStackTrace();
            }
            beanValEntry.setData(baos.toByteArray());

            OperationStatus status = null;//操作状态码
            if (isOverwrite)
                status = db.put(null, beanKeyEntry,beanValEntry);//覆盖原来的值
            else
                status = db.putNoOverwrite(null, beanKeyEntry,beanValEntry);//不允许重复key值添加
            if (status == OperationStatus.SUCCESS) {
                log.info("insert success");
                return true;
            } else if (status == OperationStatus.KEYEXIST){
                log.info("key exist");
                return false;
            } else {
                log.info("insert fail");
                return false;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (DatabaseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    public List<String> getKeys(){

        Cursor cursor = null;//游标
        List<String> keys = new LinkedList<String>();//链表列表

        CursorConfig cc = new CursorConfig();//游标配置
        cc.setReadCommitted(true);//设置隔离级别

        try {
            if(cursor==null)
                cursor = db.openCursor(null, cc);

            DatabaseEntry beanKeyEntry = new DatabaseEntry();
            DatabaseEntry beanValueEntry = new DatabaseEntry();

            if (cursor.getFirst(beanKeyEntry,beanValueEntry,LockMode.DEFAULT)==OperationStatus.SUCCESS){
                String key = new String(beanKeyEntry.getData(),"UTF-8");
                keys.add(key);

                while (cursor.getNext(beanKeyEntry, beanValueEntry, LockMode.DEFAULT) == OperationStatus.SUCCESS)
                {
                    key = new String(beanKeyEntry.getData(), "UTF-8");
                    keys.add(key);
                }
            }
            cursor.close();

        }catch (DatabaseException e){

        }catch (UnsupportedEncodingException e){

        }
        return keys;
    }

    public boolean put(K key, V value){

        try {
            DatabaseEntry beanKeyEntry = new DatabaseEntry(key.toString().getBytes("utf-8"));
            DatabaseEntry beanValEntry = new DatabaseEntry();
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(value);
            } catch (IOException e) {
                e.printStackTrace();
            }
            beanValEntry.setData(baos.toByteArray());
            OperationStatus status = db.put(null, beanKeyEntry,beanValEntry);
            if (status == OperationStatus.SUCCESS) {
                return true;
            } else {
                return false;
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (DatabaseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    public Object get(K key){

        Object value = null;
        try {
            DatabaseEntry beanKeyEntry = new DatabaseEntry(key.toString().getBytes("utf-8"));
            DatabaseEntry beanValueEntry = new DatabaseEntry();
            OperationStatus status = db.get(null, beanKeyEntry, beanValueEntry,LockMode.DEFAULT);
            if (status == OperationStatus.SUCCESS) {
                ByteArrayInputStream bais = new ByteArrayInputStream(beanValueEntry.getData());
                try {
                    ObjectInputStream ois = new ObjectInputStream(bais);
                    value = ois.readObject();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (DatabaseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return value;

    }

    public boolean del(K key){
        DatabaseEntry beanKeyEntry;
        try {
            beanKeyEntry = new DatabaseEntry(key.toString().getBytes("utf-8"));
            if(OperationStatus.SUCCESS == db.delete(null, beanKeyEntry))
                return true;
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (DatabaseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }

    public long size(){
        try {
            return db.count();
        } catch (DatabaseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return -1;
    }

    public void close(){
        try {
            db.close();
            env.cleanLog();
            env.close();
        } catch (DatabaseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}
